//
//  templateArr.hpp
//  learnC++
//
//  Created by liuzhibing on 2018/6/20.
//  Copyright © 2018年 yunfan.com. All rights reserved.
//

#ifndef templateArr_hpp
#define templateArr_hpp

#include <stdio.h>
#include <iostream>
#include <cassert>

template <class T>// This is a template class, the user will provide the data type for T

class Array {
private:
    int m_length;
    T *m_data;
    
public:
    Array(){
        
    }
    
    Array(int length){
        m_data = new T[length]();
        m_length = length;
    }
    
    ~Array(){
        delete [] m_data;
    }
    
    void erase(){
        delete [] m_data;
        
        m_data = nullptr;
        m_length = 0;
    }
    
    T &operator[](int index){
        assert(index > 0 && index < m_length);
        return m_data[index];
    }
    
    //在类外定义的成员函数需要自己的模板声明
    int getArrLength();
    
    //也可以指截在定义里面写，更方便
//    int getArrLength(){
//        return m_length;
//    }
    bool getBool(){
        return false;
    }
    
    friend std::ostream &operator<<(std::ostream &out,Array<T> &c){

        for (int i = 0; i < c.m_length; ++i) {
            out << c.m_data[i] << "\n";
        }

        return out;
    }
    
};

template <typename T>
//类名是Array<T>
int Array<T>::getArrLength(){
    return m_length;
}

//为了使编译器使用模板，它必须同时看到模板定义（不仅仅是声明）和用于实例化模板的模板类型。还要记住，C ++单独编译文件。当在main中包含Array.h头文件时，模板类定义被复制到main.cpp中。当编译器发现我们需要两个模板实例Array <int>和Array <double>时，它将实例化这些实例，并将它们作为main.cpp的一部分进行编译。但是，当它分开编译Array.cpp时，它会忘记我们需要一个Array <int>和Array <double>，所以模板函数永远不会实例化。因此，我们得到一个链接器错误，因为编译器找不到Array <int> :: getLength（）或Array <double> :: getLength（）的定义。
//有几种方法可以解决该问题 http://www.learncpp.com/cpp-tutorial/133-template-classes/

/*
 Array<int> iArr(10);
 Array<double> dArr(10);
 
 int length = iArr.getArrLength();
 for (int i = 0; i < length; ++i) {
 iArr[i] = i;
 dArr[i] = i + 0.5;
 }
 
 std::cout << iArr << dArr;
  bool res = iArr.getBool();
 */

#endif /* templateArr_hpp */
